package com.ssy.lingxi.system.service.impl;

import com.ssy.lingxi.common.constant.CommonConstant;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.member.merchant.api.feign.paas.MenuControllerFeign;
import com.ssy.lingxi.member.merchant.api.feign.paas.RoleControllerFeign;
import com.ssy.lingxi.member.merchant.api.model.vo.paas.MenuButtonDeleteVO;
import com.ssy.lingxi.member.merchant.api.model.vo.paas.MenuButtonVO;
import com.ssy.lingxi.member.merchant.api.model.vo.paas.RoleAuthVO;
import com.ssy.lingxi.system.common.SystemConstant;
import com.ssy.lingxi.system.dao.MenuRepository;
import com.ssy.lingxi.system.dao.RoleMenuRepository;
import com.ssy.lingxi.system.dao.RoleRepository;
import com.ssy.lingxi.system.dto.request.*;
import com.ssy.lingxi.system.dto.response.*;
import com.ssy.lingxi.system.entity.Menu;
import com.ssy.lingxi.system.entity.Role;
import com.ssy.lingxi.system.entity.RoleMenu;
import com.ssy.lingxi.system.model.constant.MenuConstants;
import com.ssy.lingxi.system.model.request.MenuSourceVO;
import com.ssy.lingxi.system.service.MenuService;
import com.ssy.lingxi.system.utils.ObjectUtil;
import com.ssy.lingxi.system.utils.UserDetailsUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Example;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class MenuServiceImpl implements MenuService {
    @Resource
    UserDetailsUtil userDetailsUtil;

    @Resource
    RoleRepository roleRepository;

    @Resource
    MenuRepository menuRepository;

    @Resource
    RoleMenuRepository roleMenuRepository;

    @Resource
    MenuControllerFeign menuControllerFeign;

    @Resource
    RoleControllerFeign roleControllerFeign;

    @Resource
    JdbcTemplate jdbcTemplate;

    /**
     * 查询所有权限菜单列表
     * @param sourceVO 接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<List<MenuResponse>> menuList(MenuSourceVO sourceVO) {
        List<Menu> all = menuRepository.findBySource(sourceVO.getSource());
        List<MenuResponse> menuResponses = new ArrayList<>();
        all.forEach(menu -> {
            MenuResponse menuResponse = new MenuResponse();
            BeanUtils.copyProperties(menu, menuResponse);
            menuResponse.setKey(menu.getId() + "");
            menuResponses.add(menuResponse);
        });
        //去重 排序
        List<MenuResponse> collect = menuResponses.stream().filter(v -> v.getType() == SystemConstant.MuenType.MEUN).collect(Collectors.toList());
        List<MenuResponse> menuResponseList = collect.stream().filter(ObjectUtil.distinctByKey(MenuResponse::getId)).collect(Collectors.toList()).stream().sorted(Comparator.comparing(MenuResponse::getSort)).collect(Collectors.toList());
        Map<Long, List<MenuResponse>> menuMap = menuResponseList.stream().collect(Collectors.groupingBy(MenuResponse::getParentId));
        //顶级菜单
        List<MenuResponse> menus = menuMap.get(0L);
        if (null != menus && menus.size() > 0) {
            menus.forEach(menu -> menuResponseList(menuMap, menu.getId(), menu));
        }
        return Wrapper.success(menus);
    }

    /**
     * 添加权限菜单实体类
     * @param httpServletRequest Http请求
     * @param request 接口参数
     * @return 操作结果
     */
    @Transactional
    @Override
    public Wrapper<Void> menuAdd(HttpServletRequest httpServletRequest, MenuAddRequest request) {
        MiddlegroundUserLoginResponse loginUserDetails = userDetailsUtil.getLoginUserDetails(httpServletRequest);

        if(StringUtils.isEmpty(request.getUrl()) || !request.getUrl().startsWith("/") || request.getUrl().contains(" ") || (request.getUrl().length() > 1 && request.getUrl().endsWith("/"))) {
            return Wrapper.fail("菜单Url必须以“/”开始，不能以“/”结束，且不能有空格");
        }

        if(menuRepository.existsByUrlAndSourceAndType(request.getUrl(), request.getSource(), SystemConstant.MuenType.MEUN)) {
            return Wrapper.fail("菜单Url已经存在");
        }

        if(!CollectionUtils.isEmpty(request.getButtons()) && request.getButtons().stream().filter(buttonAddRequest -> !StringUtils.isEmpty(buttonAddRequest.getButtonCode()) && !StringUtils.isEmpty(buttonAddRequest.getButtonCode().trim())).anyMatch(buttonAddRequest -> menuRepository.existsByUrlAndSourceAndType(buttonAddRequest.getButtonUrl().trim(), request.getSource(), SystemConstant.MuenType.BUTTON))) {
            return Wrapper.fail("按钮Url已经存在");
        }

        //顶级菜单不能有“up"属性
        if(request.getParentId().equals(0L) && !CollectionUtils.isEmpty(request.getAttrs()) && request.getAttrs().keySet().stream().map(String::toLowerCase).collect(Collectors.toList()).contains("up")) {
            return Wrapper.fail("顶级菜单不能有up属性");
        }

        //上级菜单不能有“up”属性
        if(!request.getParentId().equals(0L)) {
            Menu upperMenu = menuRepository.findById(request.getParentId()).orElse(null);
            if(upperMenu == null) {
                return Wrapper.fail("上级菜单不存在");
            }

            if(upperMenu.getUp().equals(1)) {
                return Wrapper.fail("上级菜单有up属性，不能创建下级菜单");
            }
        }

        //判断数据权限的参数
        if(request.getDataAuthConfig() != null && !request.getDataAuthConfig().equals(0) && !request.getDataAuthConfig().equals(1)) {
            return Wrapper.fail("数据权限参数取值为0或1");
        }

        //同级菜单顺序加1
        List<Menu> sameLevelList = menuRepository.findByParentIdAndSourceAndSortGreaterThanEqual(request.getParentId(), request.getSource(), request.getSort());
        if(!CollectionUtils.isEmpty(sameLevelList)) {
            Integer minSort = Collections.min(sameLevelList.stream().map(Menu::getSort).collect(Collectors.toList()));
            if(request.getSort().equals(minSort)) {
                for (Menu menu1 : sameLevelList) {
                    minSort = minSort + 1;
                    menu1.setSort(minSort);
                }
            }
            menuRepository.saveAll(sameLevelList);
        }

        Menu newMenu = new Menu();
        newMenu.setCreateRoleId(loginUserDetails.getId());
        newMenu.setCreateTime(System.currentTimeMillis());
        newMenu.setDescribe(request.getDescribe());
        newMenu.setParentId(request.getParentId());
        newMenu.setState(CommonConstant.State.STATE_START);
        newMenu.setUrl(request.getUrl());
        newMenu.setTitle(request.getTitle());
        newMenu.setSort(request.getSort());
        newMenu.setType(SystemConstant.MuenType.MEUN);
        newMenu.setCode(request.getCode());
        newMenu.setUp(request.getUp());
        newMenu.setDataAuthConfig(request.getDataAuthConfig() == null ? 0 : request.getDataAuthConfig());
        newMenu.setSource(request.getSource());

        newMenu.setAttrs(request.getAttrs() == null ? new HashMap<>() : request.getAttrs());
        menuRepository.saveAndFlush(newMenu);

        List<Menu> list = new ArrayList<>();
        if (!CollectionUtils.isEmpty(request.getButtons())) {
            request.getButtons().forEach(buttonAddRequest -> {
                Menu button = new Menu();
                button.setCreateRoleId(loginUserDetails.getId());
                button.setCreateTime(System.currentTimeMillis());
                button.setDescribe(StringUtils.isEmpty(buttonAddRequest.getButtonExplain()) ? "" : buttonAddRequest.getButtonExplain().trim());
                button.setParentId(newMenu.getId());
                button.setState(CommonConstant.State.STATE_START);
                button.setUrl(StringUtils.isEmpty(buttonAddRequest.getButtonUrl()) ? "" : buttonAddRequest.getButtonUrl().trim());
                button.setTitle(StringUtils.isEmpty(buttonAddRequest.getButtonName()) ? "" : buttonAddRequest.getButtonName().trim());
                button.setType(SystemConstant.MuenType.BUTTON);
                button.setCode(StringUtils.isEmpty(buttonAddRequest.getButtonCode()) ? "" : buttonAddRequest.getButtonCode().trim());
                button.setUp(0);
                button.setSource(request.getSource());
                button.setAttrs(buttonAddRequest.getAttrs() == null ? new HashMap<>() : buttonAddRequest.getAttrs());
                list.add(button);
            });
            menuRepository.saveAll(list);
        }

        MenuButtonVO menuButtonVO = new MenuButtonVO();
        menuButtonVO.setPaasId(newMenu.getId());
        menuButtonVO.setParentId(newMenu.getParentId());
        menuButtonVO.setCode(newMenu.getCode());
        menuButtonVO.setOrder(newMenu.getSort());
        menuButtonVO.setTitle(newMenu.getTitle());
        menuButtonVO.setUrl(newMenu.getUrl());
        menuButtonVO.setRemark(newMenu.getDescribe());
        menuButtonVO.setStatus(CommonConstant.State.STATE_START);
        menuButtonVO.setUp(newMenu.getUp());
        menuButtonVO.setSource(newMenu.getSource());
        menuButtonVO.setAttrs(newMenu.getAttrs());
        menuButtonVO.setDataAuthConfig(newMenu.getDataAuthConfig());
        if (CollectionUtils.isEmpty(list)) {
            menuButtonVO.setButtons(new ArrayList<>());
        } else {
            menuButtonVO.setButtons(list.stream().map(b -> {
                MenuButtonVO.ButtonAddVO buttonAddVO = new MenuButtonVO.ButtonAddVO();
                buttonAddVO.setPaasId(b.getId());
                buttonAddVO.setName(b.getTitle());
                buttonAddVO.setUrl(b.getUrl());
                buttonAddVO.setRemark(b.getDescribe());
                buttonAddVO.setCode(b.getCode());
                buttonAddVO.setAttrs(b.getAttrs());
                return buttonAddVO;
            }).collect(Collectors.toList()));
        }

        try {
            Wrapper<?> result = menuControllerFeign.addMenu(menuButtonVO);
            if(result.getCode() != ResponseCode.SUCCESS.getCode()) {
                //手动触发事务回滚
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return Wrapper.fail(result.getCode(), result.getMessage());
            }
        } catch (Exception ignored) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return Wrapper.fail(ResponseCode.SERVICE_MERCHANT_MEMBER_ERROR);
        }

        return Wrapper.success();
    }

    /**
     * 修改菜单
     * @param request 接口参数
     * @param httpServletRequest Http请求
     * @return 操作结果
     */
    @Transactional
    @Override
    public Wrapper<Void> menuUpdate(MenuUpdateRequest request, HttpServletRequest httpServletRequest) {
        MiddlegroundUserLoginResponse loginUserDetails = userDetailsUtil.getLoginUserDetails(httpServletRequest);
        Menu menu = menuRepository.findById(request.getId()).orElse(null);
        if (menu == null) {
            return Wrapper.fail("菜单不存在请检查参数");
        }

        if(StringUtils.isEmpty(request.getUrl()) || !request.getUrl().startsWith("/") || request.getUrl().contains(" ") || (request.getUrl().length() > 1 && request.getUrl().endsWith("/"))) {
            return Wrapper.fail("菜单Url必须以“/”开始，不能以“/”结束，且不能有空格");
        }

        if(menuRepository.existsByCodeAndSourceAndTypeAndIdNot(request.getUrl(), request.getSource(), SystemConstant.MuenType.MEUN, menu.getId())) {
            return Wrapper.fail("菜单Url已经存在");
        }

        //顶级菜单不能有“up"属性
        if(request.getParentId().equals(0L) && !CollectionUtils.isEmpty(request.getAttrs()) && request.getAttrs().keySet().stream().map(String::toLowerCase).collect(Collectors.toList()).contains("up")) {
            return Wrapper.fail("顶级菜单不能有up属性");
        }

        //上级菜单不能有“up”属性
        if(!menu.getParentId().equals(0L)) {
            Menu upperMenu = menuRepository.findById(menu.getParentId()).orElse(null);
            if(upperMenu == null) {
                return Wrapper.fail("上级菜单不存在");
            }

            if(upperMenu.getUp().equals(1)) {
                return Wrapper.fail("上级菜单有up属性，不能创建下级菜单");
            }
        }

        List<Menu> buttonList = menuRepository.findAllByParentIdAndTypeEquals(request.getId(), SystemConstant.MuenType.BUTTON);
        if(!CollectionUtils.isEmpty(buttonList) && !CollectionUtils.isEmpty(request.getButtons())) {
            List<Long> buttonIdList = buttonList.stream().map(Menu::getId).collect(Collectors.toList());
            List<String> buttonCodeList = request.getButtons().stream().filter(buttonAddRequest -> !StringUtils.isEmpty(buttonAddRequest.getButtonCode()) && !StringUtils.isEmpty(buttonAddRequest.getButtonCode().trim())).map(ButtonAddRequest::getButtonCode).collect(Collectors.toList());
            if(menuRepository.existsBySourceAndTypeAndCodeInAndIdNotIn(request.getSource(), SystemConstant.MuenType.BUTTON, buttonCodeList, buttonIdList)) {
                return Wrapper.fail("按钮编码已经存在");
            }
        }

        if(request.getDataAuthConfig() != null && !request.getDataAuthConfig().equals(0) && !request.getDataAuthConfig().equals(1)) {
            return Wrapper.fail("是否可配置数据权限参数错误，取值为0或1");
        }

        //同级菜单顺序加1
        List<Menu> sameLevelList = menuRepository.findByParentIdAndSourceAndSortGreaterThanEqualAndIdNot(menu.getParentId(), menu.getSource(), request.getSort(), menu.getId());
        if(!CollectionUtils.isEmpty(sameLevelList)) {
            Integer minSort = Collections.min(sameLevelList.stream().map(Menu::getSort).collect(Collectors.toList()));
            if(request.getSort().equals(minSort)) {
                for (Menu menu1 : sameLevelList) {
                    minSort = minSort + 1;
                    menu1.setSort(minSort);
                }
            }
            menuRepository.saveAll(sameLevelList);
        }

        menu.setDescribe(request.getDescribe());
        menu.setUpdateTime(System.currentTimeMillis());
        menu.setUrl(request.getUrl().trim());
        menu.setTitle(request.getTitle());
        menu.setSort(request.getSort());
        menu.setUp(request.getUp());
        menu.setCode(request.getCode());
        menu.setSource(request.getSource());
        menu.setDataAuthConfig(request.getDataAuthConfig() == null ? 0 : request.getDataAuthConfig());
        menu.setAttrs(request.getAttrs() == null ? new HashMap<>() : request.getAttrs());
        menuRepository.saveAndFlush(menu);

        //menuRepository.deleteAllByParentIdAndTypeEquals(save.getId(), SystemConstant.MuenType.BUTTON);
        menuRepository.deleteAll(buttonList);

        List<Menu> list = new ArrayList<>();
        if (!CollectionUtils.isEmpty(request.getButtons())) {
            request.getButtons().forEach(buttonAddRequest -> {
                Menu button = new Menu();
                button.setCreateRoleId(loginUserDetails.getId());
                button.setCreateTime(System.currentTimeMillis());
                button.setDescribe(StringUtils.isEmpty(buttonAddRequest.getButtonExplain()) ? "" : buttonAddRequest.getButtonExplain().trim());
                button.setParentId(menu.getId());
                button.setState(CommonConstant.State.STATE_START);
                button.setUrl(StringUtils.isEmpty(buttonAddRequest.getButtonUrl()) ? "" : buttonAddRequest.getButtonUrl().trim());
                button.setTitle(StringUtils.isEmpty(buttonAddRequest.getButtonName()) ? "" : buttonAddRequest.getButtonName().trim());
                button.setType(SystemConstant.MuenType.BUTTON);
                button.setSource(request.getSource());
                button.setUp(0);
                button.setCode(StringUtils.isEmpty(buttonAddRequest.getButtonCode()) ? "" : buttonAddRequest.getButtonCode().trim());
                button.setAttrs(buttonAddRequest.getAttrs() == null ? new HashMap<>() : buttonAddRequest.getAttrs());
                list.add(button);
            });
            menuRepository.saveAll(list);
        }

        MenuButtonVO menuButtonVO = new MenuButtonVO();
        menuButtonVO.setPaasId(menu.getId());
        menuButtonVO.setParentId(menu.getParentId());
        menuButtonVO.setCode(menu.getCode());
        menuButtonVO.setOrder(menu.getSort());
        menuButtonVO.setTitle(menu.getTitle());
        menuButtonVO.setUrl(menu.getUrl());
        menuButtonVO.setUp(menu.getUp());
        menuButtonVO.setRemark(menu.getDescribe());
        menuButtonVO.setStatus(CommonConstant.State.STATE_START);
        menuButtonVO.setSource(menu.getSource());
        menuButtonVO.setAttrs(menu.getAttrs());
        menuButtonVO.setDataAuthConfig(menu.getDataAuthConfig());
        if (CollectionUtils.isEmpty(list)) {
            menuButtonVO.setButtons(new ArrayList<>());
        } else {
            menuButtonVO.setButtons(list.stream().map(b -> {
                MenuButtonVO.ButtonAddVO buttonAddVO = new MenuButtonVO.ButtonAddVO();
                buttonAddVO.setPaasId(b.getId());
                buttonAddVO.setName(b.getTitle());
                buttonAddVO.setUrl(b.getUrl());
                buttonAddVO.setRemark(b.getDescribe());
                buttonAddVO.setCode(b.getCode());
                buttonAddVO.setAttrs(b.getAttrs());
                return buttonAddVO;
            }).collect(Collectors.toList()));
        }

        try {
            Wrapper<?> result = menuControllerFeign.updateMenu(menuButtonVO);
            if (result.getCode() != ResponseCode.SUCCESS.getCode()) {
                //手动触发事务回滚
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return Wrapper.fail(result.getCode(), result.getMessage());
            }
        } catch (Exception ignored) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return Wrapper.fail(ResponseCode.SERVICE_MERCHANT_MEMBER_ERROR);
        }

        return Wrapper.success();
    }

    /**
     * 删除权限菜单
     * @param request 接口参数
     * @return 操作结果
     */
    @Transactional
    @Override
    public Wrapper<Void> menuDelete(MenuDeleteRequest request) {
        Menu menu = menuRepository.findById(request.getId()).orElse(null);
        if (menu == null) {
            return Wrapper.success();
        }

        if(menuRepository.existsByParentId(request.getId())) {
            return Wrapper.fail("请先删除子菜单！");
        }

        List<RoleMenu> roleMenuList = roleMenuRepository.findByMenuId(menu.getId());
        if(!CollectionUtils.isEmpty(roleMenuList)) {
            List<Long> roleIds = roleMenuList.stream().map(RoleMenu::getRoleId).distinct().collect(Collectors.toList());
            List<Role> roleList = roleRepository.findAllById(roleIds);
            String roleNames = roleList.stream().map(Role::getName).collect(Collectors.joining(","));
            return Wrapper.fail("菜单已经与角色：" + roleNames + " 设置了权限，请先删除角色的菜单权限");
        }

        menuRepository.deleteById(request.getId());

        MenuButtonDeleteVO deleteVO = new MenuButtonDeleteVO();
        deleteVO.setPaasId(request.getId());
        Wrapper<?> result = menuControllerFeign.deleteMenu(deleteVO);
        if(result.getCode() != ResponseCode.SUCCESS.getCode()) {
            //手动触发事务回滚
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }

        return Wrapper.success();
    }

    /**
     * 根据角色ID查询权限菜单列表
     * @param httpServletRequest Http请求
     * @param request 接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<MenuListByRoleIdResponse> menuListByRoleId(HttpServletRequest httpServletRequest, MenuRequest request) {
        MenuListByRoleIdResponse response = new MenuListByRoleIdResponse();
        RoleMenu roleMenu = new RoleMenu();
        roleMenu.setRoleId(request.getRoleId());
        Example<RoleMenu> example = Example.of(roleMenu);
        List<RoleMenu> all1 = roleMenuRepository.findAll(example);
        List<Long> ids = all1.stream().map(RoleMenu::getMenuId).collect(Collectors.toList());
        List<Menu> allById = menuRepository.findAllById(ids);
        List<Menu> collect = allById.stream().filter(v -> v.getType() == SystemConstant.MuenType.MEUN).collect(Collectors.toList());
        Set<Long> set = collect.stream().map(Menu::getId).collect(Collectors.toSet());
        response.setIds(new ArrayList<>(set));
        return Wrapper.success(response);
    }

    /**
     * 配置角色权限
     * @param request 接口参数
     * @return 操作结果
     */
    @Transactional
    @Override
    public Wrapper<Void> menuRoleBinding(MenuBindingRoleRequest request) {

        Role role = roleRepository.findById(request.getRoleId()).orElse(null);
        if(role == null) {
            return Wrapper.fail(ResponseCode.BUSINESS_ERROR, "会员角色不存在");
        }

        List<Menu> menuList = menuRepository.findAll();
        if(!CollectionUtils.isEmpty(request.getMenus())) {
            if(!request.getMenus().stream().allMatch(menuId -> menuList.stream().anyMatch(menu -> menu.getId().equals(menuId)))) {
                return Wrapper.fail(ResponseCode.BUSINESS_ERROR, "菜单不存在");
            }
        }

        List<Menu> checkMenuList = menuList.stream().filter(menu -> request.getMenus().contains(menu.getId())).collect(Collectors.toList());

        if("平台".equals(role.getName())) {
            if(checkMenuList.stream().anyMatch(menu -> !menu.getSource().equals(99))) {
                return Wrapper.fail(ResponseCode.BUSINESS_ERROR, "平台角色只能添加平台后台的菜单权限");
            }
        } else {
            if(checkMenuList.stream().anyMatch(menu -> menu.getSource().equals(99))) {
                return Wrapper.fail(ResponseCode.BUSINESS_ERROR, "会员角色不能添加平台后台的菜单权限");
            }
        }

        //先删除再添加
        List<Long> menus = request.getMenus();
        List<Long> list = roleMenuRepository.findByRoleId(request.getRoleId()).stream().map(RoleMenu::getMenuId).collect(Collectors.toList());
        List<Menu> allById = menuRepository.findAllById(list);
        List<Long> collect = allById.stream().filter(v -> v.getType() == SystemConstant.MuenType.MEUN).map(Menu::getId).collect(Collectors.toList());
        roleMenuRepository.deleteAllByRoleIdAndMenuIdIn(request.getRoleId(), collect);
        List<RoleMenu> roleMenus = new ArrayList<>();
        menus.forEach(id -> {
            RoleMenu roleMenu = new RoleMenu();
            roleMenu.setRoleId(request.getRoleId());
            roleMenu.setMenuId(id);
            roleMenus.add(roleMenu);
        });
        roleMenuRepository.saveAll(roleMenus);

        return Wrapper.success();
    }

    /**
     * 配置角色按钮权限
     * @param request 接口参数
     * @return 操作结果
     */
    @Transactional
    @Override
    public Wrapper<Void> menuRoleBindingButton(MenuRoleBindingButtonRequest request) {
        //先删除再添加
        List<Long> menus = CollectionUtils.isEmpty(request.getMenus()) ? new ArrayList<>() : request.getMenus();
        List<Menu> menuList = menuRepository.findAllByTypeEqualsAndParentId(SystemConstant.MuenType.BUTTON, request.getParentId());
        List<Long> collect = menuList.stream().map(Menu::getId).collect(Collectors.toList());
        roleMenuRepository.deleteAllByRoleIdAndMenuIdIn(request.getRoleId(), collect);
        List<RoleMenu> roleMenus = new ArrayList<>();
        menus.forEach(id -> {
            RoleMenu roleMenu = new RoleMenu();
            roleMenu.setRoleId(request.getRoleId());
            roleMenu.setMenuId(id);
            roleMenus.add(roleMenu);
        });

        if(roleMenus.size() > 0){
            roleMenuRepository.saveAll(roleMenus);
        }

        return Wrapper.success();
    }

    /**
     * 向会员服务同步指定角色的权限配置
     *
     * @param request 角色Id
     * @return 同步结果
     */
    @Override
    public Wrapper<Void> syncRoleBinding(MenuRequest request) {
        if(Objects.isNull(request) || Objects.isNull(request.getRoleId())) {
            return Wrapper.fail("角色Id不能为空");
        }

        List<Long> list = roleMenuRepository.findByRoleId(request.getRoleId()).stream().map(RoleMenu::getMenuId).collect(Collectors.toList());

        if(CollectionUtils.isEmpty(list)) {
            return Wrapper.success();
        }

        Map<Long, List<Long>> map = new HashMap<>();
        //查询角色关联的所有菜单和按钮
        List<Menu> roleMenuButtonList = menuRepository.findAllById(list);
        List<Menu> roleMenuList = roleMenuButtonList.stream().filter(m -> m.getType() == SystemConstant.MuenType.MEUN).collect(Collectors.toList());
        roleMenuList.forEach(roleMenu -> {
            List<Long> buttonIdList = roleMenuButtonList.stream().filter(m -> m.getType() == SystemConstant.MuenType.BUTTON && m.getParentId().equals(roleMenu.getId())).map(Menu::getId).collect(Collectors.toList());
            map.put(roleMenu.getId(), buttonIdList);
        });

        RoleAuthVO roleAuthVO = new RoleAuthVO();
        roleAuthVO.setAuth(map);
        roleAuthVO.setId(request.getRoleId());

        try {
            Wrapper<?> result = roleControllerFeign.setRoleAuth(roleAuthVO);
            if (result.getCode() != ResponseCode.SUCCESS.getCode()) {
                return Wrapper.fail(result.getCode(), result.getMessage());
            }
        } catch (Exception ingored) {
            return Wrapper.fail(ResponseCode.SERVICE_MERCHANT_MEMBER_ERROR);
        }

        return Wrapper.success();
    }

    /**
     * 向会员服务同步所有角色的权限配置
     */
    @Override
    public Wrapper<Void> syncAllRoleBinding() {
        List<Role> roleList = roleRepository.findAll();
        int total = roleList.size();
        int index = 1;
        for (Role role : roleList) {
            System.out.println(index + "/" + total + " => " + role.getName());
            List<RoleMenu> roleMenuList = roleMenuRepository.findByRoleId(role.getId());
            if(CollectionUtils.isEmpty(roleList)) {
                index++;
                continue;
            }

            List<Long> menus = roleMenuList.stream().map(RoleMenu::getMenuId).collect(Collectors.toList());
            if(CollectionUtils.isEmpty(menus)) {
                System.out.println(role.getName() + " => 没有权限关联");
                index++;
                continue;
            }

            Map<Long, List<Long>> map = new HashMap<>();
            //根据父ID查询子Id集合
            List<Menu> buttonKeyList = menuRepository.findAllByTypeEqualsAndParentIdIn(MenuConstants.MenuType.BUTTON, menus);
            menus.forEach(id -> {
                List<Long> buttonKey = buttonKeyList.stream().filter(b -> b.getParentId().equals(id)).map(Menu::getId).collect(Collectors.toList());
                map.put(id, buttonKey);
            });

            RoleAuthVO roleAuthVO = new RoleAuthVO();
            roleAuthVO.setAuth(map);
            roleAuthVO.setId(role.getId());

            Wrapper<?> result = roleControllerFeign.setRoleAuth(roleAuthVO);
            if(result.getCode() != ResponseCode.SUCCESS.getCode()) {
                return Wrapper.fail(result.getCode(), result.getMessage());
            }

            index++;
        }

        return Wrapper.success();
    }

    /**
     * 根据会员ID查询按钮
     * @param request 接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<MenuListByRoleIdResponse> menuRoleButtonList(MenuRoleButtonListRequest request) {
        MenuListByRoleIdResponse response = new MenuListByRoleIdResponse();
        StringBuilder sbList = new StringBuilder();
        StringBuilder sbCondition = new StringBuilder();
        sbList.append("SELECT m.id as id,m.id as key,m.title as title,m.url as url  from cf_menu m left join cf_role_menu rm on rm.menu_id=m.id where m.type =2 ");
        if (null != request && null != request.getMemberId()) {
            sbCondition.append(" AND  rm.role_id =  ");
            sbCondition.append(request.getMemberId());
        }
        if (null != request && null != request.getMenuId()) {
            sbCondition.append(" AND  m.parent_id = ");
            sbCondition.append(request.getMenuId());
        }
        sbList.append(sbCondition.toString());

        //List<MenuRoleButtonListResponse> menuRoleButtonListResponses = jdbcTemplate.query(sbList.toString(), new BeanPropertyRowMapper(MenuRoleButtonListResponse.class));
        List<MenuRoleButtonListResponse> menuRoleButtonListResponses = jdbcTemplate.query(sbList.toString(), new BeanPropertyRowMapper<>(MenuRoleButtonListResponse.class));
        response.setIds(menuRoleButtonListResponses.stream().map(MenuRoleButtonListResponse::getId).collect(Collectors.toList()));
        return Wrapper.success(response);
    }



    /**
     * 平台菜单管理-查询菜单详情
     * @param request 接口参数
     * @param httpServletRequest Http请求
     * @return 查询结果
     */
    @Override
    public Wrapper<MenuMemberDetailsResponse> menuDetails(MenuMemberDetailsRequest request, HttpServletRequest httpServletRequest) {
        MenuMemberDetailsResponse menuMemberDetailsResponse = new MenuMemberDetailsResponse();
        Menu menu = menuRepository.findById(request.getId()).orElse(null);
        if (menu == null) {
            return Wrapper.fail("菜单详情不存在");
        }

        menuMemberDetailsResponse.setId(menu.getId());
        menuMemberDetailsResponse.setDescribe(menu.getDescribe());
        menuMemberDetailsResponse.setKey(menu.getId() + "");
        menuMemberDetailsResponse.setParentId(menu.getParentId());
        menuMemberDetailsResponse.setSort(menu.getSort());
        menuMemberDetailsResponse.setUrl(menu.getUrl());
        menuMemberDetailsResponse.setTitle(menu.getTitle());
        menuMemberDetailsResponse.setCode(menu.getCode());
        menuMemberDetailsResponse.setUp(menu.getUp());
        menuMemberDetailsResponse.setSource(menu.getSource());
        menuMemberDetailsResponse.setAttrs(menu.getAttrs());
        menuMemberDetailsResponse.setDataAuthConfig(menu.getDataAuthConfig());
        List<Menu> buttonList = menuRepository.findAllByParentIdAndTypeEquals(menu.getId(), SystemConstant.MuenType.BUTTON);
        List<MenuRoleButtonListResponse> buttons = buttonList.stream().map(button ->{
            MenuRoleButtonListResponse menuRoleButtonListResponse = new MenuRoleButtonListResponse();
            menuRoleButtonListResponse.setId(button.getId());
            menuRoleButtonListResponse.setButtonUrl(button.getUrl());
            menuRoleButtonListResponse.setButtonName(button.getTitle());
            menuRoleButtonListResponse.setButtonExplain(button.getDescribe());
            menuRoleButtonListResponse.setButtonCode(button.getCode());
            menuRoleButtonListResponse.setAttrs(button.getAttrs());
            return menuRoleButtonListResponse;
        }).collect(Collectors.toList());

        menuMemberDetailsResponse.setButtons(buttons);
        return Wrapper.success(menuMemberDetailsResponse);
    }

    /**
     * 以树形菜单形式查询菜单列表（与会员服务登陆接口返回的权限菜单列表相同结构）
     *
     * @param request 接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<List<Map<String, Object>>> treeMenuAsMemberLogin(MenuSourceVO request) {
        List<Menu> allList = menuRepository.findBySource(request.getSource());
        if(CollectionUtils.isEmpty(allList)) {
            return Wrapper.success(new ArrayList<>());
        }

        List<Menu> menuList = allList.stream().filter(m -> m.getType() == MenuConstants.MenuType.MENU).collect(Collectors.toList());
        List<Menu> buttonList = allList.stream().filter(m -> m.getType() == MenuConstants.MenuType.BUTTON).collect(Collectors.toList());

        List<Map<String, Object>> resultList = new ArrayList<>();

        //找到第一级菜单，第一级菜单不会有“up”属性
        List<Menu> topList = menuList.stream().filter(t -> t.getParentId().equals(0L)).sorted(Comparator.comparingInt(Menu::getSort)).collect(Collectors.toList());

        //循环、递归构建树
        topList.forEach(top -> {
            List<Map<String, Object>> buttons = buttonList.stream().filter(b -> b.getParentId().equals(top.getId())).map(b -> {
                Map<String, Object> buttonMap = new HashMap<>();
                buttonMap.put("name", b.getTitle());
                buttonMap.put("path", b.getUrl());
                buttonMap.put("buttonCode", StringUtils.isEmpty(b.getCode()) ? "" : b.getCode());
//                if(!StringUtils.isEmpty(b.getCode())) {
//                    buttonMap.put("component", b.getCode());
//                }
                if(!CollectionUtils.isEmpty(b.getAttrs())) {
                    buttonMap.putAll(b.getAttrs());
                }
                return buttonMap;
            }).collect(Collectors.toList());

            Map<String, Object> menuMap = new HashMap<>();
            menuMap.put("name", top.getTitle());
            menuMap.put("path", top.getUrl());
            if(!StringUtils.isEmpty(top.getCode())) {
                menuMap.put("component", top.getCode());
            }
            menuMap.put("relationParentCode",Optional.ofNullable(top.getAttrs()).map(m -> Objects.nonNull(m.get("relationParentCode")) ? m.get("relationParentCode") : "").orElse(""));
            menuMap.put("btns", buttons);
            if(!CollectionUtils.isEmpty(top.getAttrs())) {
                menuMap.putAll(top.getAttrs());
            }

            //上移一层的菜单
            List<Map<String, Object>> upList = new ArrayList<>();

            recurseBuildClientAuthTree(menuMap, top, menuList, buttonList, upList);

            resultList.add(menuMap);

            if(!CollectionUtils.isEmpty(upList)) {
                resultList.addAll(upList);
            }
        });

        return Wrapper.success(resultList);
    }

    @SuppressWarnings("unchecked")
    private static void recurseBuildClientAuthTree(Map<String, Object> upperMenuMap, Menu upperMenu , List<Menu> menuList, List<Menu> buttonList,  List<Map<String, Object>> upList) {

//        List<Map<String, Object>> emptyChildren = new ArrayList<>();
//        upperMenuMap.put("routes", emptyChildren);

        List<Menu> subList = menuList.stream().filter(s -> s.getParentId().equals(upperMenu.getId())).sorted(Comparator.comparingInt(Menu::getSort)).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(subList)) {
            return;
        }

        for (Menu sub : subList) {
            List<Map<String, Object>> buttons = buttonList.stream().filter(b -> b.getParentId().equals(sub.getId())).map(b -> {
                Map<String, Object> buttonMap = new HashMap<>();
                buttonMap.put("name", b.getTitle());
                buttonMap.put("path", b.getUrl());
                buttonMap.put("buttonCode", StringUtils.isEmpty(b.getCode()) ? "" : b.getCode());
//                if(!StringUtils.isEmpty(b.getCode())) {
//                    buttonMap.put("component", b.getCode());
//                }
                if(!CollectionUtils.isEmpty(b.getAttrs())) {
                    buttonMap.putAll(b.getAttrs());
                }
                return buttonMap;
            }).collect(Collectors.toList());

            Map<String, Object> subMenu = new HashMap<>();
            subMenu.put("name", sub.getTitle());
            subMenu.put("path", sub.getUrl());
            if(!StringUtils.isEmpty(sub.getCode())) {
                subMenu.put("component", sub.getCode());
            }
            subMenu.put("relationParentCode",Optional.ofNullable(sub.getAttrs()).map(m -> Objects.nonNull(m.get("relationParentCode")) ? m.get("relationParentCode") : "").orElse(""));
            subMenu.put("btns", buttons);
            if(!CollectionUtils.isEmpty(sub.getAttrs())) {
                subMenu.putAll(sub.getAttrs());
            }

            if(sub.getUp().equals(1)) {
                upList.add(subMenu);
            } else {
                List<Map<String, Object>> children;
                if(upperMenuMap.containsKey("routes")) {
                    children = (List<Map<String, Object>>) upperMenuMap.get("routes");
                } else {
                    children = new ArrayList<>();
                    upperMenuMap.put("routes", children);
                }

                children.add(subMenu);
            }

            //上移一层的菜单
            List<Map<String, Object>> sameLevelList = new ArrayList<>();
            recurseBuildClientAuthTree(subMenu, sub, menuList, buttonList, sameLevelList);

            if(!CollectionUtils.isEmpty(sameLevelList)) {
                List<Map<String, Object>> children;
                if(upperMenuMap.containsKey("routes")) {
                    children = (List<Map<String, Object>>) upperMenuMap.get("routes");
                } else {
                    children = new ArrayList<>();
                    upperMenuMap.put("routes", children);
                }
                children.addAll(sameLevelList);
            }
        }
    }

    /**
     * 递归查询菜单的下级菜单
     */
    private void menuResponseList(Map<Long, List<MenuResponse>> collect, Long id, MenuResponse menuResponse) {
        List<MenuResponse> menuResponses = collect.get(id);
        if (null != menuResponses && menuResponses.size() > 0) {
            menuResponses.forEach(menu -> {
                menuResponse.setChildren(menuResponses);
                menuResponseList(collect, menu.getId(), menu);
            });
        }
    }


    @Override
    public Wrapper<Map<Long, String>> initMenuRelationParentCode(Integer source){
        List<Menu> allList = menuRepository.findBySource(source);
        if(CollectionUtils.isEmpty(allList)) {
            return Wrapper.success();
        }

        // 查询出的某类型菜单
        List<Menu> menuList = allList.stream().filter(m -> m.getType() == MenuConstants.MenuType.MENU).collect(Collectors.toList());
        // 顶级菜单集合
        List<Menu> topMenuList = menuList.stream().filter(menu -> Objects.isNull(menu.getParentId()) || menu.getParentId() == 0).collect(Collectors.toList());
        // 子菜单集合
        List<Menu> chileMenuList = menuList.stream().filter(menu -> Objects.nonNull(menu.getParentId()) && menu.getParentId() != 0).collect(Collectors.toList());
        // parentId - menu
        Map<Long, List<Menu>> childMap = chileMenuList.stream().collect(Collectors.groupingBy(Menu::getParentId));
        // 需要修改的数据 menuId - relationParentCode
        Map<Long, String> dataMap = new TreeMap<>();
        // 递归遍历数据
        for (Menu menu : topMenuList) {
            // 生成relationParentCode
            String relationParentCode = createRelationParentCode(source, menu.getUrl());
            if (Objects.nonNull(menu.getAttrs())) {
                menu.getAttrs().put("relationParentCode", relationParentCode);
            }

            recurse(relationParentCode, childMap, menu, dataMap);
        }

        // 修改子级菜单数据
        List<Menu> saveChildMenuList = menuRepository.findAllById(dataMap.keySet()).stream().peek(m -> {
            String relationParentCode = dataMap.get(m.getId());
            if (Objects.nonNull(m.getAttrs())) {
                m.getAttrs().put("relationParentCode", StringUtils.isEmpty(relationParentCode) ? "" : relationParentCode);
            }
        }).collect(Collectors.toList());

        // 更新顶级菜单和自己菜单的数据
        topMenuList.addAll(saveChildMenuList);
        menuRepository.saveAll(topMenuList);

       return Wrapper.success(dataMap);
    }

    private void recurse(String relationParentCode, Map<Long, List<Menu>> childMap, Menu upperMenu, Map<Long, String> dataMap){
        List<Menu> childList = childMap.get(upperMenu.getId());
        if (CollectionUtils.isEmpty(childList)) {
            return ;
        }

        for (Menu menu : childList) {
            dataMap.put(menu.getId(), relationParentCode);

            // 递归遍历
            recurse(relationParentCode, childMap, menu, dataMap);
        }
    }

    /**
     * 对业务平台和平台后台的url分别处理
     */
    private String createRelationParentCode(Integer source, String url){
        String relationParentCode = "";
        if (StringUtils.isNotEmpty(url)) {
            if (url.startsWith("/")) {
                url = url.substring(1);
            }
            String[] splitUrl = url.split("/");
            if (source == 1) {
                // 业务平台菜单
                relationParentCode = splitUrl.length >= 2 ? splitUrl[1] : "";
            } else if(source == 99){
                // 平台后台菜单
                relationParentCode = splitUrl.length >= 1 ? splitUrl[0] : "";
            }
        }
        return relationParentCode;
    }

}
